package com.ruoyi.manage.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.OrderFileType;
import com.ruoyi.common.enums.OrderStatus;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileTypeUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.manage.domain.OrderFileEntity;
import com.ruoyi.manage.domain.Orders;
import com.ruoyi.manage.entity.order.OrderFileVo;
import com.ruoyi.manage.mapper.OrderFileMapper;
import com.ruoyi.manage.mapper.OrdersMapper;
import com.ruoyi.manage.service.IOrdersService;
import com.ruoyi.manage.service.IOrderFileService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.rmi.ServerException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class IOrderFileServiceImpl
        extends ServiceImpl<OrderFileMapper, OrderFileEntity>
        implements IOrderFileService {

    private final OrdersMapper ordersMapper;

    @Override
    public void uploadFile(MultipartFile file, String orderId, String fileType) {
        if (file.isEmpty() || file.getSize() <= 0) {
            try {
                throw new ServiceException(StringUtils.format("请选择文件"));
            } catch (Exception e) {
                log.error("文件上传失败", e);
            }
        }

        try {
            // 获取文件名
            String originalFilename = file.getOriginalFilename();
            //获取文件后缀
            String fileSuffix = FileTypeUtils.getFileType(originalFilename);
            if (!ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(originalFilename))) {
                throw new ServiceException("请上传正确文件");
            }
            //本地资源路径
            String localPath = RuoYiConfig.getProfile();
            //定义文件唯一标识
            String fileCode = FileUtils.generateUid();
            //完整路径
            String integrityPath = localPath + "/" + fileCode + "." + fileSuffix;
            File waitUpload = new File(integrityPath);
            boolean exists = waitUpload.exists();
            if (exists) {
                throw new ServiceException("文件名称已存在,请修改后上传");
            }
            // 将文件保存到指定文件夹
            file.transferTo(new File(integrityPath));
            //信息保存
            saveUserFile(integrityPath,originalFilename, orderId, fileType, fileCode);
            //订单状态修改
            updateStatus(orderId, fileType);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void updateStatus(String orderId, String fileType) {
        Orders orders = this.ordersMapper.selectByOrderId(orderId);
        switch (Objects.requireNonNull(OrderFileType.getByCode(fileType))) {
            case CREATE:
            case UPDATE:
                orders.setOrderStatus(OrderStatus.COMPLETED.getCode());
                orders.setUpdateTime(new Date());
                break;
            case UPDATE_REQUIREMENT:
                orders.setOrderStatus(OrderStatus.TO_BE_MODIFIED.getCode());
                orders.setUpdateTime(new Date());
                break;
                default:
        }
        this.ordersMapper.updateOrders(orders);
    }

    @Override
    public List<OrderFileVo> findOrderFile(String orderId) {

        List<OrderFileVo> resultList = Lists.newArrayList();

        List<SysDictData> dictDataList = DictUtils.getDictCache("file_type");
        Map<String, SysDictData> dictDataMap = dictDataList.
                stream().
                collect(Collectors.toMap(SysDictData::getDictValue,
                        Function.identity(),
                        (newDic, oldDic) -> newDic));

        List<OrderFileEntity> list = this.list(new LambdaQueryWrapper<OrderFileEntity>().
                eq(OrderFileEntity::getOrderId, orderId).
                orderByDesc(OrderFileEntity::getCreateTime));

        if (CollUtil.isNotEmpty(list)) {
            list.forEach(item -> {
                OrderFileVo resultOrderFile = new OrderFileVo();
                resultOrderFile.setOrderId(orderId);
                resultOrderFile.setRemark(item.getRemark());
                String fileType = item.getFileType();
                SysDictData sysDictData = dictDataMap.get(fileType);
                resultOrderFile.setFileType(sysDictData.getDictLabel());
                resultOrderFile.setFileName(item.getFileName());
                resultOrderFile.setCreateTime(item.getCreateTime());
                resultOrderFile.setFileId(String.valueOf(item.getId()));
                resultOrderFile.setFileCode(item.getFileCode());
                resultList.add(resultOrderFile);
            });
        }

        return resultList;
    }

    @Override
    public void orderFileDown(HttpServletResponse response, String fileCode) {
        try {

            OrderFileEntity orderFileEntity = this.
                    getOne(new LambdaQueryWrapper<OrderFileEntity>().
                            eq(OrderFileEntity::getFileCode, fileCode));
            if (ObjectUtil.isNull(orderFileEntity)) {
                throw new ServerException("资源文件不存在!");
            }
            String fileName = orderFileEntity.getFileName();
            boolean allowDown = FileUtils.checkAllowDownload(fileName);
            if (!allowDown) {
                throw new Exception(StringUtils.format("资源文件({})非法，不允许下载。 ", fileName));
            }
            // 本地资源路径
            String localPath = RuoYiConfig.getProfile();
            //获取后缀
            String fileSuffix = FileTypeUtils.getFileType(fileName);
            String resource = Constants.RESOURCE_PREFIX + "/" + orderFileEntity.getFileCode() + "." + fileSuffix;
            // 数据库资源地址
            String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, fileName);
            FileUtils.writeBytes(downloadPath, response.getOutputStream());
        } catch (Exception e) {
            log.error("下载文件失败", e);
        }

    }

    private void saveUserFile(String integrityPath, String originalFilename, String orderId, String fileType, String fileCode) {
        //获取当前登陆用户

        OrderFileEntity orderFileEntity = new OrderFileEntity();

        orderFileEntity.setOrderId(orderId);
        orderFileEntity.setFileType(fileType);
        orderFileEntity.setFilePath(integrityPath);
        orderFileEntity.setFileName(originalFilename);
        orderFileEntity.setFileCode(fileCode);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        orderFileEntity.setCreateBy(loginUser.getUsername());
        orderFileEntity.setCreateTime(new Date());
        orderFileEntity.setUpdateBy(loginUser.getUsername());
        orderFileEntity.setUpdateTime(new Date());

        this.save(orderFileEntity);
    }
}
